package parallel;

import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.*;

/**
 * @author Xu,
 * @data 2020/12/9，
 * @time 15:34
 * 在单线程以及把需要用到的数据都提取到myData.txt中，不用反复提取。
 * 处理临界的日志数据，即前半部分子线程的in车辆和后半部分子线程的out车辆的合并；
 * 在前半部分子线程找到in而找不掉对应out的时候把in数据放到一个新建集合critical中，在
 * 后半部分子线程找完对应in、out后将集合critical逐一与剩下的out匹配
 * 写一个计时日志。目前未实现保存功能。完成
 */
public class LogMiningParallel {
    private static ArrayList<ArrayList<String>> log = new ArrayList<>();
    private static ArrayList<ArrayList<String>> myLog = new ArrayList<>();
    private static ArrayList<ArrayList<String>> critical = new ArrayList<>();
    private static int count = 0;
    private static long sumTime = 0;
    private static String s1,s2,s3;

    private static boolean finalI = true;
    public static void main(String[] args) {
        SimpleDateFormat sdf0 = new SimpleDateFormat("HH:mm:ss.SSS");
        s1 = sdf0.format(new Date());
        long start = System.currentTimeMillis();
        String path = "./src/carsLog.txt";
        readData(path);
        s2 = sdf0.format(new Date());
        System.out.println("数据导入data时间：" + (System.currentTimeMillis() - start)/1000.0 + " s");
        searchData();
        parkTime();
        System.out.println("进出车次数：" + count/2);
        System.out.println("累计停放秒数：" + sumTime + " s");
        s3 = sdf0.format(new Date());
        createTxt();
        long end = System.currentTimeMillis();
        System.out.println("runtime: " + (end - start)/1000.0 + " s");
    }

    /**
     * 停车计数、计时
     */
    public  static void parkTime(){
        byte[] lock = new byte[0];
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        ExecutorService executorService = new ThreadPoolExecutor(2, 3, 0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(10),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        executorService.execute(
                new Runnable(){
                    @Override
                    public void run() {
                        Date date1 = null;
                        Date date2 = null;
                        synchronized (lock) {
                                if(!finalI) {
                                    try {
                                        lock.wait();
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                                for (int i=0; i<myLog.size()/2; i++){
                                    if(myLog.get(i).get(3).equals("in")){
                                        try {
                                            date1 = sdf.parse(myLog.get(i).get(0));
                                        } catch (ParseException e) {
                                            e.printStackTrace();
                                        }
                                        int j;
                                        for(j=i; j<myLog.size()/2; j++){
                                            if(myLog.get(j).get(2).equals(myLog.get(i).get(2)) && "out".equals(myLog.get(j).get(3))){
                                                try {
                                                    date2 = sdf.parse(myLog.get(j).get(0));
                                                } catch (ParseException e) {
                                                    e.printStackTrace();
                                                }
                                                sumTime += (date2.getTime() - date1.getTime())/1000;
                                                break;
                                            }
                                        }
                                        if (j == myLog.size()/2) {
                                            critical.add(myLog.get(i));
                                        }
                                    }
                                }
                                finalI = false;
                                lock.notify();
                            }
                        }
                });
        executorService.execute(
                new Runnable(){
                    @Override
                    public void run() {
                        Date date1 = null;
                        Date date2 = null;
                            synchronized (lock){
                                if(finalI){
                                    try {
                                        lock.wait();
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                                for (int i=myLog.size()/2; i<myLog.size(); i++){
                                    if(myLog.get(i).get(3).equals("in")){

                                        try {
                                            date1 = sdf.parse(myLog.get(i).get(0));
                                        } catch (ParseException e) {
                                            e.printStackTrace();
                                        }
                                        for(int j=i; j<myLog.size(); j++){
                                            if(myLog.get(j).get(2).equals(myLog.get(i).get(2)) && "out".equals(myLog.get(j).get(3))){
                                                try {
                                                    date2 = sdf.parse(myLog.get(j).get(0));
                                                } catch (ParseException e) {
                                                    e.printStackTrace();
                                                }
                                                sumTime += (date2.getTime() - date1.getTime())/1000;
                                                break;
                                            }
                                        }
                                    }
                                }
                                for(int k=0;k<critical.size();k++){
                                    for(int m=myLog.size()/2;m<myLog.size();m++){
                                        try {
                                            date1 = sdf.parse(critical.get(k).get(0));
                                        } catch (ParseException e) {
                                            e.printStackTrace();
                                        }
                                        if(critical.get(k).get(2).equals(myLog.get(m).get(2))){
                                            try {
                                                date2 = sdf.parse(myLog.get(m).get(0));
                                            } catch (ParseException e) {
                                                e.printStackTrace();
                                            }
                                            sumTime += (date2.getTime() - date1.getTime())/1000;
                                            break;
                                        }
                                    }
                                }
                                finalI = true;
                                lock.notify();
                            }
                        }

                });
        executorService.shutdown();
        while(!executorService.isTerminated()){ }
    }

    /**
     * 找到自己学号的停车场，并统计进出次数
     * 记录每辆车的停放时间的总和
     */
    public static void searchData(){
        for(int i=0;i<log.size();i++){
            if("201825010318".equals(log.get(i).get(1))){
                myLog.add(log.get(i));
                count++;
            }
        }

    }

    /**
     * 读取数据
     * @param path
     * @return
     */
    public  static void readData(String path){
        ArrayList<String> t = null;
        try {
            InputStreamReader isr = new InputStreamReader(new FileInputStream(new File(path)));
            BufferedReader br = new BufferedReader(isr);
            String str = null;
            while((str = br.readLine()) != null){
                t = new ArrayList<String>();
                String[] str1 = str.split(",");
                for(int i = 0; i < str1.length ; i++) {
                    t.add(str1[i]);
                }
                log.add(t);
            }
            br.close();
            isr.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("读取文件内容出错！");
        }
    }

    /**
     * check一下
     */
    public static void show1(){
        for(int i=0;i<myLog.size();i++){
            System.out.println(myLog.get(i));
        }
    }

    /**
     * 生成.txt文件
     */
    public static void createTxt() {
        String path = "./src/output.txt";
        BufferedWriter bufferedWriter = null;
        FileOutputStream outputStream = null;
        StringBuffer stringBuffer;
        try {
            outputStream = new FileOutputStream(path,true);
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
                        stringBuffer = new StringBuffer();
                        stringBuffer.append("Start ReadFile:" + s1 + "\n");
                        stringBuffer.append("End ReadFile:" + s2 + "\n");
                        stringBuffer.append("End Process:" + s3 + "\n");
                        stringBuffer.append("\n");
            bufferedWriter.write(stringBuffer.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedWriter.close();
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
